/*
 * @Author: LVGRAPE
 * @LastEditors: LVGRAPE
 */
/*
 * @Author: LVGRAPE
 * @LastEditors: LVGRAPE
 */
#ifndef __DELAY_H
#define __DELAY_H
#ifdef __cplusplus
extern "C"
{
#endif
#include "at32f4xx.h"
	typedef uint32_t time_ms;
	typedef uint32_t time_us;

	void SysTick_Init(uint32_t div);
	void delay_us(uint16_t us);
	void delay_ms(uint32_t ms);
	// void delayUs(uint16_t ms);
	// void delayMs(uint16_t ms);
	time_us micros(void);
	time_ms millis(void);
	void set_millis_calibration(int32_t calibration);
	void set_micros_calibration(int32_t calibration);
	#define DECLARE_TASK_PERIOD(NAME, PERIOD) \
    static time_ms NAME##_period = PERIOD;  \
    static time_ms NAME##_time = 0

	#define CHECK_TASK_PERIOD_MS(NAME) if (millis() >= (NAME##_period + NAME##_time))
	#define CHECK_TASK_PERIOD_US(NAME) if (micros() >= (NAME##_period + NAME##_time))
	#define UPDATE_TASK_TIME_MS(NAME) NAME##_time = millis()
	#define UPDATE_TASK_TIME_US(NAME) NAME##_time = micros()
	// set BASEPRI and BASEPRI_MAX register, but do not create memory barrier
	__attribute__((always_inline)) static inline void __set_BASEPRI_nb(uint32_t basePri)
	{
		__ASM volatile("\tMSR basepri, %0\n"
					   :
					   : "r"(basePri));
	}

	__attribute__((always_inline)) static inline void __set_BASEPRI_MAX_nb(uint32_t basePri)
	{
		__ASM volatile("\tMSR basepri_max, %0\n"
					   :
					   : "r"(basePri));
	}
	// cleanup BASEPRI restore function, with global memory barrier
	static inline void __basepriRestoreMem(uint8_t *val)
	{
		__set_BASEPRI(*val);
	}
	// set BASEPRI_MAX function, with global memory barrier, returns true
	static inline uint8_t __basepriSetMemRetVal(uint8_t prio)
	{
		__set_BASEPRI_MAX(prio);
		return 1;
	}
	// cleanup BASEPRI restore function, no memory barrier
	static inline void __basepriRestore(uint8_t *val)
	{
		__set_BASEPRI_nb(*val);
	}

	// utility macros to join/split priority
#define NVIC_PRIORITY_GROUPING NVIC_PriorityGroup_2
#define NVIC_BUILD_PRIORITY(base, sub) (((((base) << (4 - (7 - (NVIC_PRIORITY_GROUPING >> 8)))) | ((sub) & (0x0f >> (7 - (NVIC_PRIORITY_GROUPING >> 8))))) << 4) & 0xf0)
#define NVIC_PRIORITY_BASE(prio) (((prio) >> (4 - (7 - (NVIC_PRIORITY_GROUPING >> 8)))) >> 4)
#define NVIC_PRIORITY_SUB(prio) (((prio) & (0x0f >> (7 - (NVIC_PRIORITY_GROUPING >> 8)))) >> 4)
#define NVIC_PRIO_MAX NVIC_BUILD_PRIORITY(0, 1)
// Run block with elevated BASEPRI (using BASEPRI_MAX), restoring BASEPRI on exit. All exit paths are handled
// Full memory barrier is placed at start and exit of block
#define ATOMIC_BLOCK(prio) for (uint8_t __basepri_save __attribute__((__cleanup__(__basepriRestoreMem))) = __get_BASEPRI(), \
								__ToDo = __basepriSetMemRetVal(prio);                                                       \
								__ToDo; __ToDo = 0)
#define delayMicroseconds(x) delay_us(x)
#define delay(x) delay_ms(x)
#ifdef __cplusplus
}
#endif
#endif
